package com.kichina.parking.module.message.socket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.kichina.parking.module.message.socket.bean.BaseSocketResponse;
import com.kichina.parking.module.message.socket.exception.MessageDealException;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetSocket;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

import static org.springframework.beans.factory.config.ConfigurableBeanFactory.SCOPE_PROTOTYPE;

/**
 * @author : <a href="https://iiiii.run">xiaohan.yuan</a>
 * @version :    1.0
 * @description : socket消息处理器
 * @date :    2021-09-10 18:09
 */
@Component
@Scope(value = SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
@Slf4j
public class SocketMessageHandler {

    /**
     * 断包字符串缓存区
     */

    public static ConcurrentHashMap<String, List<String>> breakPackageStrMap = new ConcurrentHashMap<>();

    private final List<IMessageHandler> socketMessageHandlers;

    public SocketMessageHandler(List<IMessageHandler> socketMessageHandlers) {
        this.socketMessageHandlers = socketMessageHandlers;
    }

    public void handle(Buffer buffer, NetSocket netSocket) {

        if (!buffer.toString().contains("heartbeat")){
            log.info("收到消息：{}", buffer.toString());
        }
        //服务端消息发送
        //先转换为Object实体
        Object object = null;
        try {
            object = JSON.parseObject(buffer.toString(), Object.class);
            dealNetSocket(netSocket, object);
        }catch (JSONException e) {
            //保存断包的数据
            if (Objects.isNull(breakPackageStrMap.get(netSocket.writeHandlerID()))){
                List<String> breakPackageStrList = Lists.newArrayList(buffer.toString());
                breakPackageStrMap.put(netSocket.writeHandlerID(), breakPackageStrList);
            } else {
                breakPackageStrMap.get(netSocket.writeHandlerID()).add(buffer.toString());
            }
            List<String> breakPackageStrList = breakPackageStrMap.get(netSocket.writeHandlerID());
            //断包处理,缓存中只保留了一个包的数据
            StringBuilder objectStr = new StringBuilder();
            //前包字符串获取
            if (CollectionUtils.isNotEmpty(breakPackageStrList)) {
                for (int i = 0; i < breakPackageStrList.size() - 1; i++) {
                    String frontPackageStr = breakPackageStrList.get(i);
                    objectStr.append(frontPackageStr);
                }
            }
            objectStr.append(buffer.toString());



            try {
                if (objectStr.toString().contains("}")){
                    //断包粘包消息处理
                    dealMessagePacketBreak(netSocket, objectStr.toString());
                }

            } catch (JSONException f) {
                log.info("断包缓存数量为：{}", breakPackageStrList.size());
                //防止混乱断包，导致数据累积
                if (breakPackageStrList.size() >= 5) {
                    breakPackageStrMap.remove(netSocket.writeHandlerID());
                }
            }



        }catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * @param netSocket 通道
     * @param objectStr 消息
     * @author Surging
     * @Description
     * @Return void
     * @date 17:18 2022-09-19
     **/
    private void dealMessagePacketBreak(NetSocket netSocket, String objectStr) {
        Object object;
        String substring = objectStr.substring(0, objectStr.indexOf("}") + 1);
        log.info("拼装消息：{}", substring);
        if ("".equals(substring)){
            return;
        }
        object = JSON.parseObject(substring, Object.class);
        dealNetSocket(netSocket, object);
        log.info("数据拼装成功移除断包缓存");
        //移除缓存中的所有断包缓存
        breakPackageStrMap.remove(netSocket.writeHandlerID());
        if ((objectStr.indexOf("}") ==(objectStr.length()-1))){

        } else {
            //添加剩余字符
            objectStr = objectStr.substring(objectStr.indexOf("}") + 1);
            if (substring.contains("}")){
                dealMessagePacketBreak(netSocket, objectStr);
            }else {
                List<String> breakPackageStrList1 = Lists.newArrayList(objectStr);
                breakPackageStrMap.put(netSocket.writeHandlerID(), breakPackageStrList1);
            }
        }
    }

    /**
     * @param netSocket 通道
     * @param object 消息实体
     * @author Surging
     * @Description
     * @Return void
     * @date 17:21 2022-09-19
     **/
    private void dealNetSocket(NetSocket netSocket, Object object) {
        JSONObject jsonObject = JSON.parseObject(JSONObject.toJSONString(object));
        // 不合法字符串不进行处理
        if (!jsonObject.containsKey("service")) {
            return;
        }
        for (IMessageHandler iWebSocketMessageHandler : socketMessageHandlers) {
            if (iWebSocketMessageHandler.check(jsonObject)){
                try {
                    iWebSocketMessageHandler.handler(jsonObject, netSocket);
                } catch (MessageDealException e) {
                    SocketStorageDeal.sendResponse(netSocket, BaseSocketResponse.buildFailedNoOrderId(jsonObject.getString("service")));
                }
                if (iWebSocketMessageHandler.interrupt()){
                    return;
                }
            }
        }
    }
}
